import java.io.*;
import java.util.HashMap;
import java.util.Map;

public class Scanner
{
    private StringReader inputReader;

    private Map<Character, TokenId> setOfSymbols;
    private Map<String, TokenId> setOfCommands;
    private Map<String, TokenId> setOfOperators;

    private Character currentChar;
    private boolean isEof = false;

    public Scanner(String codeLine)
    {
        inputReader = new StringReader(codeLine);

        currentChar = ' ';
        InitSetOfSymbols();
        InitSetOfOperators();
        InitSetOfCommands();
    }

    public Token GetNextToken()
            throws RuntimeException
    {
        String tokenInfo = "";
        TokenId tokenId = TokenId.UNDEFINED;
        while (tokenId == TokenId.UNDEFINED)
        {
            if (isEof)
            {
                tokenId = TokenId.EOF;
            }
            else
            {
                if (Character.isWhitespace(currentChar))
                {
                    GetNextChar();
                }
                else if (setOfSymbols.containsKey(currentChar))
                {
                    tokenId = setOfSymbols.get(currentChar);
                    GetNextChar();
                }
                else if (Character.isAlphabetic(currentChar))
                {
                    String word = "";
                    while (Character.isAlphabetic(currentChar))
                    {
                        word += currentChar;
                        GetNextChar();
                    }

                    if (setOfOperators.containsKey(word))
                    {
                        tokenId = setOfOperators.get(word);
                    }
                    else if (setOfCommands.containsKey(word))
                    {
                        tokenId = setOfCommands.get(word);
                    }
                    else
                    {
                        tokenId = TokenId.VARIABLE;
                    }
                    tokenInfo = word;
                }
                else
                {
                    char unexpectedSymbol = currentChar;
                    GetNextChar();
                    throw new RuntimeException("Unexpected symbol: " + unexpectedSymbol);
                }
            }
        }
        return new Token(tokenId, tokenInfo);
    }

    private void InitSetOfSymbols()
    {
        setOfSymbols = new HashMap<Character, TokenId>();
        setOfSymbols.put(';', TokenId.SEMICOLON);
        setOfSymbols.put('(', TokenId.LEFT_ROUND_BRACKET);
        setOfSymbols.put(')', TokenId.RIGHT_ROUND_BRACKET);
    }

    private void InitSetOfCommands()
    {
        setOfCommands = new HashMap<String, TokenId>();
        setOfCommands.put("right", TokenId.RIGHT);
        setOfCommands.put("left", TokenId.LEFT);
        setOfCommands.put("forward", TokenId.FORWARD);
        setOfCommands.put("backward", TokenId.BACKWARD);
        setOfCommands.put("say", TokenId.SAY);
        setOfCommands.put("go", TokenId.GO);
        setOfCommands.put("stop", TokenId.STOP);
        setOfCommands.put("attack", TokenId.ATTACK);
        setOfCommands.put("work", TokenId.WORK);
    }

    private void InitSetOfOperators()
    {
        setOfOperators = new HashMap<String, TokenId>();
        setOfOperators.put("while", TokenId.WHILE);
    }

    private void GetNextChar()
    {
        try
        {
            int ch = inputReader.read();
            isEof = (ch == -1);
            currentChar = (char) ch;
        }
        catch (IOException ex)
        {
            System.out.println(ex.getMessage());
            isEof = true;
        }
    }
}
